package com.srp.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.srp.anno.Limit;
import com.srp.common.R;
import com.srp.dto.DataFileDto;
import com.srp.dto.TreeDto;
import com.srp.pojo.DataFile;
import com.srp.servise.TreeService;
import com.srp.tools.JwtUtils;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Slf4j
@RestController
@Tag(name="数据集&决策树管理")
@RequestMapping("api/tree")
public class TreeController {
    @Autowired
    private TreeService treeService;

    @Value("${files.upload.path}")
    private String basePath;
    /**
     * 上传数据集
     */
    @PostMapping("/uploadData")
    @Operation(summary = "上传数据集")
    @Transactional
    public R<Boolean> upload(
                    @Parameter(name = "file", description = "上传文件", required = true)
            @RequestHeader("token")String token, @RequestParam MultipartFile file){
        List<DataFile> list = treeService.list();
        List<String> existingNames = new ArrayList<>();
        for(DataFile dataFile:list){
            existingNames.add(dataFile.getName());
        }
        String originalFilename = file.getOriginalFilename();
        String baseFileName = originalFilename.substring(0, originalFilename.lastIndexOf('.'));
        String suffix = originalFilename.substring(originalFilename.lastIndexOf('.'));

        String newFileName = generateUniqueFileName(baseFileName, suffix, existingNames);

        // 使用uuid重新生成文件名，防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString()+suffix;
        // 创建目录对象
        File dir = new File(basePath);
        if(!dir.exists()){
            dir.mkdirs();
        }
        try{
            file.transferTo(new File(basePath+fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }

        DataFile file1 = new DataFile();
        file1.setName(newFileName);
        file1.setUrl(fileName);

        treeService.save(file1);

        // 将数据插入到user_file表中
        int id = file1.getId();

        Claims claims = JwtUtils.parseJWT(token);
        String userId = claims.get("UserId",String.class);

        log.info("userId:{},id:{}",userId,id);

        treeService.giveUserFileRight(userId,id);

        return R.success(true);
    }

    private static String generateUniqueFileName(String baseFileName, String suffix, List<String> existingFilenames) {
        String newFileName = baseFileName + suffix;

        // Check if the filename already exists
        if (existingFilenames.contains(newFileName)) {
            int index = 1;

            // Find the highest index in parentheses
            for (String existingFilename : existingFilenames) {
                if (existingFilename.startsWith(baseFileName + "(") && existingFilename.endsWith(")" + suffix)) {
                    int endIndex = existingFilename.indexOf(')');
                    int startIndex = existingFilename.lastIndexOf('(', endIndex - 1) + 1;

                    String indexStr = existingFilename.substring(startIndex, endIndex);
                    int currentIndex = Integer.parseInt(indexStr);

                    index = Math.max(index, currentIndex + 1);
                }
            }

            // Form the new filename with the incremented index
            newFileName = baseFileName + "(" + index + ")" + suffix;
        }

        return newFileName;
    }


    /**
     * 下载数据集
     * @return
     */
    @GetMapping("downloadData")
    @Operation(summary = "下载数据集")
    public R<String> downloadData(
            @RequestHeader("token")String token, @Parameter(name = "id", description = "需要下载的数据集的id", required = true)@RequestParam String id, HttpServletResponse response) throws IOException {
        // 先判断用户有没有下载权限
        // 获取userId，判断是否有删除数据集的权限
        Claims claims = JwtUtils.parseJWT(token);
        String userId = claims.get("UserId",String.class);

        // 判断是否有删除数据集的权限
        List<String> file_ids = treeService.getRight(userId);

        if(!file_ids.contains(id)){
            return R.error("文件不存在");
        }

        LambdaQueryWrapper<DataFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DataFile::getId,id);

        DataFile dataFile = treeService.getOne(lambdaQueryWrapper);
        if(dataFile==null){
            return R.error("文件不存在");
        }
        String filePath = basePath+dataFile.getUrl();
        File file = new File(filePath);
        log.info(file.getPath());

        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Length", "" + file.length());
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(dataFile.getName(), "utf-8"));
        response.setContentType("application/octet-stream");

        InputStream input = null;
        OutputStream output = null;
        try{
            input = new FileInputStream(file); //创建文件输入流对象
            output = response.getOutputStream(); //创建文件输出流对象
            byte[] buf = new byte[1024]; //定义一个字节数组作为缓冲区，并指定一次读取1024个字节
            int len; //记住读入缓冲区的字节长度
            while ((len = input.read(buf)) != -1){ //判断文件是否读完（读完后会返回-1）
                output.write(buf, 0, len); //从buf缓冲区中读取数据，从第一个字节开始读，一次读取len，并将读取出来的数据写入文件输出流对象中
            }
            input.close();
            output.close();
            return R.success("文件下载成功");
        }catch (Exception e){
            e.printStackTrace();
            input.close();
            output.close();
            return R.error("文件下载失败");
        }
    }


    /**
     * 获取数据集列表
     */
    @GetMapping("/getDataList")
    @Operation(summary = "获取数据集")
    public R<List<DataFileDto>> getDataList(@RequestHeader("token")String token){
        // 获取userId，保证只有对数据集有权限的人可以看到数据集
        Claims claims = JwtUtils.parseJWT(token);
        String userId = claims.get("UserId",String.class);
        return treeService.getDataList(userId);
//        List<DataFile> dataFiles = treeService.list();
//        List<DataFileDto> dataFileDtos = new ArrayList<>();
//        for(DataFile dataFile: dataFiles){
//            DataFileDto dto = new DataFileDto();
//            dto.setId(dataFile.getId());
//            dto.setName(dataFile.getName());
//            dataFileDtos.add(dto);
//        }
//        return R.success(dataFileDtos);
    }

    /**
     * 删除数据集
     */
    @DeleteMapping("/deleteData")
    @Operation(summary = "删除数据集")
    @Transactional
    public R<Boolean> deleteData(
            @RequestHeader("token")String token,@Parameter(name = "ids", description = "List of data IDs to be deleted, e.g., [1, 2, 3]", required = true,example = "[1, 2, 3]")@RequestBody List<String> ids){
        // 获取userId，判断是否有删除数据集的权限
        Claims claims = JwtUtils.parseJWT(token);
        String userId = claims.get("UserId",String.class);

        // 判断是否有删除数据集的权限
        List<String> file_ids = treeService.getRight(userId);

        for(String id : ids){
            if(!file_ids.contains(id)){
                return R.error("用户未拥有删除权限");
            }
        }

        for(String id:ids){
            DataFile dataFile = treeService.getById(id);
            String fileName = dataFile.getUrl().substring(dataFile.getUrl().lastIndexOf('/') + 1);
            log.info(fileName);
            File fileToDelete = new File(basePath + fileName);
            if (fileToDelete.exists()) {
                fileToDelete.delete();
            }

            boolean removed = treeService.removeById(id);
            if(removed){
                treeService.deleteRowsByFileId(id);
            }else{
                return R.error("删除失败");
            }
        }
        return R.success(true);
    }

    /**
     * 数据集重命名
     * @param token
     * @param dataFileDto
     * @return
     */
    @PostMapping("/renameDataSet")
    @Operation(summary = "数据集重命名")
    public R<String> renameDataSet(@RequestHeader("token")String token,@RequestBody DataFileDto dataFileDto){
        String fileid = dataFileDto.getId().toString();
        // 获取userId，判断是否有删除数据集的权限
        Claims claims = JwtUtils.parseJWT(token);
        String userId = claims.get("UserId",String.class);

        // 判断是否有删除数据集的权限
        List<String> file_ids = treeService.getRight(userId);
        if(!file_ids.contains(fileid)){
            return R.error("用户无权限对文件重命名");
        }

        LambdaQueryWrapper<DataFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DataFile::getId,fileid);
        DataFile dataFile = treeService.getOne(lambdaQueryWrapper);

        dataFile.setName(dataFileDto.getName());

        boolean update = treeService.updateById(dataFile);

        if(update){
            return R.success("数据集重命名成功");
        }else{
            return R.error("数据集重命名失败");
        }
    }

    /**
     * 生成决策树
     * @param token
     * @param treeId
     * @param code
     * @param fileName
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    @GetMapping("/generateTree")
    @Limit(key = "generateTree", permitsPerSecond = 1, acquirePermitsPerSecond =180, timeout = 500, timeunit = TimeUnit.MILLISECONDS,msg = "请稍后再试！")
    public R<Boolean> generateTree(@RequestHeader("token")String token,String treeId,String code, String fileName) throws IOException, InterruptedException {
        log.info(treeId);
        log.info(code);
        log.info(fileName);
        Claims claims = JwtUtils.parseJWT(token);
        //此处要大写，在工具中会自动首字符大写
        String userId = claims.get("UserId",String.class);
        log.info(userId);
        Boolean generated = treeService.generateTree(treeId,code,fileName,userId);

        if(generated){
            return R.success(true);
        }else{
            return null;
        }
    }
//    @DeleteMapping("/deleteTree")
//    public R<Boolean> deleteTree(@RequestHeader("token")String token,@RequestParam String treeId) throws IOException, InterruptedException {
//        log.info(treeId);
//        Claims claims = JwtUtils.parseJWT(token);
//        //此处要大写，在工具中会自动首字符大写
//        String userId = claims.get("UserId",String.class);
//        log.info(userId);
//        Boolean generated = treeService.deleteTree(treeId,userId);
//
//        if(generated){
//            return R.success(true);
//        }else{
//            return R.error("User does not have permission or tree is not exited");
//        }
//    }
@DeleteMapping("/deleteTree")
public R<Boolean> deleteTree(@RequestHeader("token")String token,@RequestParam List<String> treeNames) throws IOException, InterruptedException {

    Claims claims = JwtUtils.parseJWT(token);
    //此处要大写，在工具中会自动首字符大写
    String userId = claims.get("UserId",String.class);
    log.info(userId);

    Boolean generated = treeService.deleteTree(treeNames,userId);

    if(generated){
        return R.success(true);
    }else{
        return R.error("User does not have permission or tree is not exited");
    }
}
    @GetMapping("/treeList")
    @Operation(summary = "获取树列表")
    public R<List<TreeDto>> getTreeList(@RequestHeader("token")String token){
        Claims claims = JwtUtils.parseJWT(token);
        //此处要大写，在工具中会自动首字符大写
        String userId = claims.get("UserId",String.class);
        log.info(userId);
        List<TreeDto> treeDtos = treeService.getTreeList(userId);
        if(treeDtos!=null){
            return R.success(treeDtos);
        }else{
            return R.error("User does not have permission or tree is not exited");
        }
    }
    @GetMapping("/treeDetail")
    public  R<String>treeDetail(@RequestHeader("token")String token,@RequestParam String treeId){
        log.info(treeId);
        Claims claims = JwtUtils.parseJWT(token);
        //此处要大写，在工具中会自动首字符大写
        String userId = claims.get("UserId",String.class);
        log.info(userId);
        String detail = treeService.getTreeDetail(treeId,userId);
        if(detail!=null){
            return R.success(detail);
        }else{
            return R.error("User does not have permission or tree is not exited");
        }
    }
    @GetMapping("/statisticAnalysis")
    public R<Object> statisticAnalysis(@RequestParam String treeName,
                                       @RequestParam int dataId){
        return treeService.statisticAnalysis(treeName,dataId);
    }
    /**
     * 上传测试数据集
     * @param file
     * @return
     */
    @PostMapping("/uploadTestData")
    @Transactional
    public R<Boolean> uploadTestData(@RequestParam MultipartFile file){
        return treeService.uploadTestData(file);
    }

    /**
     * 下载测试数据集
     * @param id
     * @param response
     * @return
     * @throws IOException
     */
    @GetMapping("/downloadTestData")
    public R<String> downloadTestData(@RequestParam String id,HttpServletResponse response) throws IOException {
        return treeService.downloadTestData(id,response);
    }

    /**
     * 返回决策树结果
     * @param treeId
     * @param dataId
     * @param response
     * @return
     */
    @GetMapping("/getFeedback")
    @Transactional
    public R<String> getFeedback(@RequestParam String treeId,
                                       @RequestParam int dataId,HttpServletResponse response){
        return treeService.getFeedback(treeId,dataId,response);
    }


    /**
     * 获取测试集列表
     * @return
     */
    @GetMapping("/getTestDataList")
    public R<List<DataFileDto>> getTestDataList(){
        return treeService.getTestDataList();
    }

    /**
     * 删除测试集
     * @param ids
     * @return
     */
    @DeleteMapping("/deleteTestData")
    @Transactional
    public R<Boolean> deleteTestData(@RequestBody List<String> ids){
        return treeService.deleteTestData(ids);
    }

    /**
     * 获取属性名列表和各属性所填的值
     * @param treeId
     * @return
     */
    @GetMapping("/getAttribute")
    public R<Map<String,List<String>>> getAttributes(@RequestParam String treeId){
        return treeService.getAttributes(treeId);
    }

    /**
     * 前端据此生成问卷，用户填完后前端将信息发给后端，后端做出判断再回传
     * @param data
     * @return
     */
    @PostMapping("/getFeedback")
    public R<String> getFeedBack(@RequestBody Map<String,String> data,@RequestParam String treeId){
        return treeService.getFeedback(data,treeId);
    }

}
